﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
using System.IO;
using System.Security.Principal;
using System.Diagnostics;
using System.ComponentModel;
using System.Data;

//#region ctors
//#endregion ctors

//#region props
//#endregion props

//#region methods
//#endregion methods

//#region fields
//#endregion fields

namespace CommonUtils
{
	public enum VerboseLvl
	{
		kNone,
		kLow,
		kHigh
	}
	public enum Team
	{
		Undef,
		Base,
		D3D9,
		D3D10,
		D3D11,
		OGL,
		GLSL,
		Media,
		Power,
		Display,
		EcoSystem,
		uOS,
		HDA,
		NTV
	}

	public enum IntelSite
	{
		Undef,
		Hillsboro,
		Guadalajara
	}

    public enum ImportSheetColumns
    {
        kUndef,
        kPRD,
        kTRS,
        kFeature,
        kDeviceVersUsed,
        kSubFeature,
        kDTMTestName,
        kWLKVer,
        kTestExe,
        kTestBreakout,
        kCommandLine,
        kCommandLineAppend,
        kTier,
        kDescription,
        kComments,
        kSourceOnly,
        kTotalSubtests,
        kDuration,
        kTestExePath,
        kSupportPath,
        kCreator
    }
    public static class Common
    {
        #region static vars
		static Common()
		{
			RootDir = @"Larrabee_1\DTM\3D_Native";
		}
		public static string SEPARATOR = "=";
		public static double MAX_LOG_SIZE_IN_MB = 100.0;
		public static double MAX_EXTRANEOUS_SIZE_IN_MB = 10.0;
		public static double MAX_IMAGE_SIZE_IN_MB = 100.0;

        public static string UserDir = null;
        public static string DTMLogsDir = "DTMJobLogs\\";
        public static string DXLogger = "DX//Logger.xslt";
        public static string DTMImportBAT = "DTMImport.bat";

        public static bool AllowSetOptimalTestEnv = false;

		public static string NowBackendLogsDir = @"\\nowbackend\LumberYard\Storage";

		public static bool Local = false;

		public static Dictionary<string, Team> TeamsDict = new Dictionary<string, Team>()
		{
			{ "OGL", Team.OGL },
			{ "OpenGL", Team.OGL },
			{ "D3D9", Team.D3D9 },
			{ "Direct3D9", Team.D3D9 },
			{ "D3D10", Team.D3D10 },
			{ "Direct3D10", Team.D3D10 },
			{ "D3D11", Team.D3D11 },
			{ "Direct3D11", Team.D3D11 },
			{ "NTV", Team.NTV },
			{ "Native", Team.NTV },
		};

        public static ImportSheetColumns ImportSheetColumns;

        #endregion static vars

		#region props

		public static string WindowsVersion
		{
			get
			{
				System.OperatingSystem osInfo = System.Environment.OSVersion;
				string operatingSystem = "Unknown";
				switch (osInfo.Platform)
				{
					case System.PlatformID.Win32Windows:
						// Current OS is Windows - can be Windows95, 98 or ME
						switch (osInfo.Version.Minor)
						{
							case 0:
								operatingSystem = "Windows 95";
								break;
							case 10:
								operatingSystem = "Windows 98";
								break;
							case 90:
								operatingSystem = "Windows Me";
								break;
						}
						break;

					case System.PlatformID.Win32NT:
						// Current OS is Windows NT, 2000 or XP
						switch (osInfo.Version.Major)
						{
							case 3:
								operatingSystem = "Windows NT 3.51";
								break;
							case 4:
								operatingSystem = "Windows NT 4.0";
								break;
							case 5:
								switch (osInfo.Version.Minor)
								{
									case 0:
										operatingSystem = "Windows 2000";
										break;
									case 1:
										operatingSystem = "Windows XP";
										break;
								}
								break;
							case 6:
								switch (osInfo.Version.Minor)
								{
									case 0:
										operatingSystem = "Windows Vista";
										break;
									case 1:
										operatingSystem = "Windows 7";
										break;
								}
								break;
						}
						break;
				}
				return operatingSystem;
			}
		}
		public static string Username { get { return WindowsIdentity.GetCurrent().Name; } }
		public static string Documents
		{
			get
			{
				string documents = "Documents";
				if (WindowsVersion == "Windows XP")
					documents = "My Documents";
				return PathCombine(CurrUserDir, documents);
			}
		}

		public static string GoldImages { get { return @"\\jf4cfls1301.amr.corp.intel.com\Images"; } }
		public static string GoldUser { get { return @"\\jf4cfls1301.amr.corp.intel.com\Images"; } }

		public static string Drive { get; set; }
		public static string RootDir { get; set; } 
		public static string DriveAndRootDir
		{
			get { return Drive + RootDir; }
			set
			{
				Drive = value.Substring(0, 3);
				RootDir = value.Substring(3, value.Length - 3);
			}
		}
		public static string DocsDir
		{
			get { return Path.Combine(DriveAndRootDir, "Docs"); }
		}
		public static string IndicatorsDir
		{
			get { return Path.Combine(DriveAndRootDir, "Indicators"); }
		}
		public static string InputDir
		{
			get { return Path.Combine(DriveAndRootDir, "Input"); }
		}
		public static string OutputDir
		{
			get { return Path.Combine(DriveAndRootDir, "Output"); }
		}
		public static string ScriptsDir
		{
			get { return Path.Combine(DriveAndRootDir, "Scripts"); }
		}
		public static string SupportDir
		{
			get { return Path.Combine(DriveAndRootDir, "Support"); }
		}
		public static string TestDataDir
		{
			get { return Path.Combine(DriveAndRootDir, "TestData"); }
		}
		public static string TestExesDir
		{
			get { return Path.Combine(DriveAndRootDir, "TestExes"); }
		}
		public static string TestSuitesDir
		{
			get { return Path.Combine(DriveAndRootDir, "TestSuites"); }
		}
		public static string AnalysisDir
		{
			get { return Path.Combine(DriveAndRootDir, "Analysis"); }
		}
		public static string BackendImportDir
		{
			get { return Path.Combine(InputDir, "Backend_Import"); }
		}
		public static string DTMImportDir
		{
			get { return Path.Combine(OutputDir, "DTM_Import"); }
		}
		public static string QCImportDir
		{
			get { return Path.Combine(OutputDir, "QC_Import"); }
		}
		public static string PixValidationDir
		{
			get { return Path.Combine(OutputDir, "PixValidation"); }
		}
		public static string ValidationToolsDir
		{
			get { return Path.Combine(ScriptsDir, @"exe\ValidationTools"); }
		}
		public static string PixWinDir
		{
			get { return Path.Combine(ValidationToolsDir, "PixWin"); }
		}
		public static string CurrUser
		{
			get { return Path.GetFileName(CurrUserDir); }
		}
		public static string CurrUserDir
		{
			get
			{
				string currUserDir = Common.PathCombine
				(
					Environment.GetEnvironmentVariable("HOMEDRIVE"),
					Environment.GetEnvironmentVariable("HOMEPATH")
				);
				return currUserDir;
			}
		}
		public static string Desktop
		{
			get
			{
				string desktop = Common.PathCombine
				(
					CurrUserDir,
					"Desktop"
				);
				return desktop;
			}
		}
		public static string ProgramFiles
		{
			get { return @"C:\Program Files"; }
		}
		public static string ProgramFilesX86
		{
			get { return ProgramFiles + " (x86)"; }
		}
		public static string Windows
		{
			get { return @"C:\Windows"; }
		}
		public static string System32
		{
			get
			{
				string system32 = Common.PathCombine
				(
					Windows,
					"System32"
				);
				return system32;
			}
		}
		public static string DataTimeNow
		{
			get
			{
				string dateTimeNow = DateTime.Now.ToString();

				dateTimeNow = Regex.Replace(dateTimeNow, @"[/:]", ".");

				return dateTimeNow;
			}
		}
		#endregion props

		#region methods

		public static string StringToRegexPattern(string inString)
		{
			string pattern = Regex.Replace(inString, @"\\", @"\\");
			return pattern;
		}
		public static string BitView(int inValue)
		{
			string view = "";
			for (int i = 31; i >= 0; --i)
				view += ((inValue & (1 << i)) != 0) ? '1' : '0';
			return view;
		}
		public static int[] ExtractFlags(int inFlags)
		{
			List<int> flags = new List<int>();

			for (int i = 31; i >= 0 && inFlags != 0; --i)
			{
				int mask = 1 << i;
				if ( (mask & inFlags) != 0)
				{
					flags.Add(mask);
					inFlags ^= mask;
				}
			}
			return flags.ToArray();
		}
		public static string EnumName(object inEnum)
		{
			string name = "Undef";
			
			try
			{
				if (inEnum is Enum)
					name = Enum.GetName(inEnum.GetType(), inEnum);
			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }
			return name;
		}
		public static string[] GetKeys(KeyValuePair<string, object>[] inKvps)
		{
			List<string> keys = new List<string>();
			foreach (KeyValuePair<string, object> kvp in inKvps)
				keys.Add(kvp.Key);
			return keys.ToArray();
		}
		public static object[] GetValues(KeyValuePair<string, object>[] inKvps)
		{
			List<object> values = new List<object>();
			foreach (KeyValuePair<string, object> kvp in inKvps)
				values.Add(kvp.Value);
			return values.ToArray();
		}
		public static string GetWorkWeek(DateTime inDateTime)
		{
			// Intel logic for WW is:
			//	The week containing January 1st is always WW01. If the current date is in 
			//	the last week of December and that week contains Jan 1, then the WW is 01 
			//	of the following year. Years where Dec 31 falls on Saturday will have a WW53.

			string workweek = "";

			int currentYear = inDateTime.Year;
			int nextYear = currentYear + 1;

			// Get first date (Sunday) of current week
			DateTime firstDateOfCurrentWeek = inDateTime.AddDays(0 - (double)inDateTime.DayOfWeek);

			// Get Jan 1 of following year
			DateTime janFirstNextYear = DateTime.Parse("01-JAN-" + nextYear.ToString());

			// If current week contains Jan 1 of next year
			if (janFirstNextYear.Subtract(firstDateOfCurrentWeek).Days < 7)
			{
				// Current week is WW01 of next year
				workweek = (nextYear * 100 + 1).ToString();
			}
			else
			{
				// Get Jan 1 of current year
				DateTime janFirstThisYear = DateTime.Parse("01-JAN-" + currentYear.ToString());

				// Get date of Sunday WW01 this year (DayOfWeek.Sunday is 0)
				int offset = (int)janFirstThisYear.DayOfWeek;
				DateTime firstDay = janFirstThisYear.AddDays(0 - (double)offset);

				// Get number of days elapsed since WW01.0
				TimeSpan daysElapsed = inDateTime.Subtract(firstDay);

				// Divide by 7, round down, and add 1 to get WW
				int ww = daysElapsed.Days / 7 + 1;

				// Build string. Pad WW if needed.
				workweek = (currentYear * 100 + ww).ToString();
			}

			return workweek;
		}

		public static bool ConnectToGold()
		{
			bool result = ConnectToServer(_NetworkDrive, GoldImages);
			Drive = _NetworkDrive.LocalDrive+"\\";
			return result;
		}
		public static void DisconnectFromGold()
		{
			DisconnectFromServer(_NetworkDrive);
		}
		public static bool ConnectToServer(NetworkDrive inNetworkDrive, string inShareName)
		{
			return ConnectToServer(inNetworkDrive, inShareName, null, null);
		}
		public static bool ConnectToServer(NetworkDrive inNetworkDrive, string inShareName, string inUsername, string inPassword)
		{
			if (inNetworkDrive == null)
				return false;

			Dictionary<string, string> mappedDrives = inNetworkDrive.MappedDrives;
			foreach (KeyValuePair<string, string> mappedDrive in mappedDrives)
			{
				if (mappedDrive.Value == inShareName)
				{
					inNetworkDrive.ShareName = inShareName;
					inNetworkDrive.LocalDrive = mappedDrive.Key;
                    if (inNetworkDrive.IsConnected())
                    {
                        return true;
                    }
                    if (inUsername == null || inPassword == null)
                    {
                        inNetworkDrive.PromptForCredentials = true;
                        inNetworkDrive.MapDrive();
                    }
                    else
                        inNetworkDrive.MapDrive(inUsername, inPassword);
                    return true;
				}
			}

			try
			{
				for (char c = 'Z'; c >= 'A' && string.IsNullOrEmpty(inNetworkDrive.LocalDrive); --c)
				{
					bool available = true;
					foreach (string dl in inNetworkDrive.AllDrives)
					{
						if (Regex.IsMatch(dl, c.ToString()))
							available = false;
					}

					if (available)
					{
						inNetworkDrive.ShareName = inShareName;
						inNetworkDrive.LocalDrive = c.ToString();						
						if (inUsername == null || inPassword == null)
							inNetworkDrive.MapDrive();
						else
							inNetworkDrive.MapDrive(inUsername, inPassword);
						break;
					}
				}
			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }

			return !string.IsNullOrEmpty(inNetworkDrive.LocalDrive);
		}

		public static void DisconnectFromServer(NetworkDrive inNetworkDrive)
		{
			if (inNetworkDrive == null)
				return;

			try
			{
				if (inNetworkDrive.IsMapped)
				{
					inNetworkDrive.Force = true;
					inNetworkDrive.UnMapDrive();
				}
			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }
		}


		public static void SetDriveAndRootDir(string inDriveAndRootDir)
		{
			string newDriveAndRootDir = "";
			if (inDriveAndRootDir != null && inDriveAndRootDir.Length >= 3)
			{
				newDriveAndRootDir = inDriveAndRootDir;
			}
			else
			{
				string currDir = Directory.GetCurrentDirectory();
				Match match = Regex.Match(currDir, @"(.*\\3D_Native\\)(.*)");
				if (match.Success && match.Groups[1].Value.Length > 0)
				{
					string dir = PathCombine(match.Groups[1].Value, @"ValidationEnv\trunk");
					if (Directory.Exists(dir) )
						newDriveAndRootDir = dir;
				}
				else
				{
					ConnectToGold();
					return;
				}
			}
			Drive = newDriveAndRootDir.Substring(0, 3);
			RootDir = newDriveAndRootDir.Substring(3, newDriveAndRootDir.Length - Drive.Length);
		}

		public static string WildcardToRegex(string pattern)
		{
			// From http://www.codeproject.com/KB/recipes/wildcardtoregex.aspx
			return "^" + Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + "$";
		}
        public static string ClipExt(string inFilename)
        {
            string[] result = Regex.Split(inFilename, "(\\.)[^.]*$");         
            return result[0];
        }
        public static string GetExt(string inFilename)
        {
            Match result = Regex.Match(inFilename,"(\\.)[^.]*$");
            return result.Value;
        }
        public static string ClipPath(string inFilename)
        {
            string[] result = Regex.Split(inFilename, "\\/|\\");
            return result[result.Length-1];
        }
        public static string GetPath(string inFilename)
        {
            string result = "";
            Regex.Replace(inFilename, "(.*\\/|.*\\)", result);
            return result;
        }
        public static string ClipPathAndExt(string inFilename)
        {
            return ClipExt( ClipPath( inFilename ) );
        }
        public static string ClipDash(string inFilename)
        {
            string[] result = Regex.Split(inFilename, "\\-/");
            return result[1];
        }
        public static string RemoveTrailingSpaces(string inFilename)
        {
            string result = "";
            Regex.Replace(inFilename, "( +)$/", result);
            return result;
        }
        public static bool IsFilePresent(string inFilename, string inPath)
        {
            bool result = false;
            return result;
        }
        public static string GetDate()
        {
            string result = "";
            return result;
        }
        public static string GetTime()
        {
            string result = "";
            return result;
        }
        public static string GetWorkWeek()
        {
            string result = "";
            return result;
        }
        public static string CreateDateAndTimeStamp()
        {
            return "_" + GetDate() + "_" + GetTime();
		}
		public static VerboseLvl ConvertStringToVerbosity(string inString)
		{
			VerboseLvl result = VerboseLvl.kNone;

			if (Regex.IsMatch(inString, "High", RegexOptions.IgnoreCase)) result = VerboseLvl.kHigh;
			else if (Regex.IsMatch(inString, "Low", RegexOptions.IgnoreCase)) result = VerboseLvl.kLow;

			return result;
		}
		public static int ConvertStringToInt(string inString)
		{
			int result = unchecked((int)0xDEADBEEF);

			if (!Int32.TryParse(inString, out result))
				throw new Exception("TryParse failed in ConvertStringToInt");

			return result;
		}
		public static uint ConvertStringToUInt(string inString)
		{
			uint result = unchecked((uint)0xDEADBEEF);

			if (!UInt32.TryParse(inString, out result))
				throw new Exception("TryParse failed in ConvertStringToUInt");

			return result;
		}
		public static string PathCombine(params string[] inNodes)
		{
			if (Common.IsNullOrEmpty(inNodes))
				return "";

			string combinedPath = "";
			if (!string.IsNullOrEmpty(inNodes[0]))
			{

				combinedPath = inNodes[0];
				if (Regex.IsMatch(inNodes[0], "([A-Z]:)$"))
					combinedPath += "\\";
			}
			for (uint i = 1; i < inNodes.Length; ++i)
			{
				if (!string.IsNullOrEmpty(inNodes[i]) && inNodes[i] != @"\")
				{
					string node = Regex.Replace(inNodes[i], @"^\\+", "");
					combinedPath = Path.Combine(combinedPath, node);
				}
			}
			return combinedPath;
		}

		public static string PrintCommandLineArgs(string[] inArgs)
		{
			string result = "List of CommandLine Args:\n\n";

			result += "*******************************************************\n";
			result += ObjectArrayToString(inArgs, null, "\n", null);
			result += "*******************************************************\n";

			return result;
		}
		public static string OutputDataObject(DataSet inDataSet)
		{
			string result = "";
			foreach (DataTable dt in inDataSet.Tables)
				result += "DataTable:" + dt.TableName  + "\n" + OutputDataObject(dt) + "\n\n";
			return result;
		}
		public static string OutputDataObject(DataTable inDataTable)
		{
			string result = "";
			int row = 0;
			foreach (DataRow dr in inDataTable.Rows)
				result += ObjectArrayToString(dr.ItemArray, "row:" + (++row) + "  ", ", ", "\n");
			return result;
		}

		public static object[] OutputObjectArray(DataTable inDataTable)
		{
			List<object> objectArray = new List<object>();
			foreach (DataRow dr in inDataTable.Rows)
				objectArray.AddRange(dr.ItemArray);
			return objectArray.ToArray();
		}
		public static object[][] OutputObjectArrays(DataTable inDataTable)
		{
			object[][] array = null;

			int row = 0;
			int col = 0;
			int rowCount = inDataTable.Rows.Count + 1;
			int colCount = inDataTable.Columns.Count;

			array = new object[rowCount][];
			array[row] = new object[colCount];
			for (col = 0; col < colCount; ++col)
				array[row][col] = inDataTable.Columns[col].ColumnName;

			for (row = 1; row < rowCount; ++row)
				array[row] = inDataTable.Rows[row-1].ItemArray;
			return array;
		}
		//outputs line arrays to work with the old vb web svc
		public static string[] OutputLineArrays(DataTable inDataTable)
		{
			List<string> columnNames = new List<string>();
			List<string> lineArrays = new List<string>();
			foreach (DataColumn dc in inDataTable.Columns)
				columnNames.Add(dc.ColumnName);

			lineArrays.Add(ObjectArrayToString(columnNames.ToArray(), null, ",", null));
			foreach (DataRow dr in inDataTable.Rows)
				lineArrays.Add(ObjectArrayToString(dr.ItemArray, null, ",", null));
		
			return lineArrays.ToArray();
			
		}
		public static DataTable InputObjectArray(int inColumns, object[] inObjectArray)
		{
			DataTable dt = null;
			if (inObjectArray.Length % inColumns != 0)
				return dt;

			dt = new DataTable();
			while (dt.Columns.Count < inColumns)
			    dt.Columns.Add();

			int rows = inObjectArray.Length / inColumns;
			List<object> list = new List<object>(inObjectArray);

			int index = 0;
			for (int row = 0; row < rows; ++row)
			{
				List<object> line = new List<object>(list.Where( (o,i) => { return index <= i && i < index + inColumns; }));

				dt.Rows.Add(line.ToArray() );
				index += inColumns;
			}		

			return dt;
		}

		#region find files
		public static string[] FindFiles(string src, SearchOption option, bool filenameOnly, params string[] patterns)
		{
			return FindFiles(src, option, -1.0, null, filenameOnly, patterns);
		}
		public static string[] FindFiles(string src, SearchOption option, double maxFileSize, bool filenameOnly, params string[] patterns)
		{
			return FindFiles(src, option, maxFileSize, null, filenameOnly, patterns);
		}
		public static string[] FindFiles(string src, SearchOption option, string[] exclusions, bool filenameOnly, params string[] patterns)
		{
			return FindFiles(src, option, -1.0, exclusions, filenameOnly, patterns);
		}
		public static string[] FindFiles(string src, SearchOption option, double maxFileSize, string[] exclusions, bool filenameOnly, params string[] patterns)
		{
			if (Common.IsNullOrEmpty(patterns))
				throw new ArgumentException("Common.FindFiles: string[] inPatterns cannot be null or empty");

			List<string> files = new List<string>();
			try
			{
				//make sure source directory exists
				if (!Directory.Exists(src))
					return null;

				foreach (string pattern in patterns)
				{
					string[] srcFiles = Directory.GetFiles(src, pattern, option).
						Where(s =>
						{
							//dont include files that match an exclusion
							if (exclusions != null)
							{
								foreach (string ex in exclusions)
									if (Regex.IsMatch(s, Common.StringToRegexPattern(ex))) return false;
							}
							//dont include files that are too big
							if (maxFileSize > 0)
							{
								double fileSize = GetFileSizeInMB(s);
								if (fileSize > maxFileSize)
									return false;
							}
							return true;
						}).ToArray();

					// if we want the file name only- strip the path
					if (filenameOnly)
					{
						foreach (string srcFile in srcFiles)
							files.Add( Path.GetFileName(srcFile) );
					}
					else
						files.AddRange(srcFiles);
				}
			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }

			return files.ToArray();
		}
		#endregion find files

		#region copy files
		public static string[] CopyFiles(string inSrc, string inDst, SearchOption inSearchOption, params string[] inPatterns)
		{
			return CopyFiles(inSrc, inDst, null, inSearchOption, -1.0, null, inPatterns);
		}
		public static string[] CopyFiles(string inSrc, string inDst, string inRename, SearchOption inSearchOption, params string[] inPatterns)
		{
			return CopyFiles(inSrc, inDst, inRename, inSearchOption, -1.0, null, inPatterns);
		}
		public static string[] CopyFiles(string inSrc, string inDst, string inRename, SearchOption inSearchOption, double inMaxFileSize, params string[] inPatterns)
		{
			return CopyFiles(inSrc, inDst, inRename, inSearchOption, inMaxFileSize, null, inPatterns);
		}
		public static string[] CopyFiles(string inSrc, string inDst, SearchOption inSearchOption, string[] inExclusions, params string[] inPatterns)
		{
			return CopyFiles(inSrc, inDst, null, inSearchOption, -1.0, inExclusions, inPatterns);
		}
		public static string[] CopyFiles(string inSrc, string inDst, string inRename, SearchOption inSearchOption, double inMaxFileSize, string[] inExclusions, params string[] inPatterns)
		{
			List<string> files = new List<string>();
			try
			{
				//get all of the files to copy but make sure it is not the name of the entry assembly...
				string[] srcFiles = FindFiles(inSrc, inSearchOption, inMaxFileSize, inExclusions, false, inPatterns).
					Where(f => { return Path.GetFileNameWithoutExtension(f) != Assembly.GetEntryAssembly().GetName().Name; }).ToArray();

				foreach (string srcFile in srcFiles)
				{
					//look for any unique parts of the path to preserve the file structure
					string dstFile = inDst;
					if (inSearchOption == SearchOption.AllDirectories)
					{
						string a = Common.StringToRegexPattern(inSrc);
						string z = Common.StringToRegexPattern(Path.GetFileName(srcFile));
						string unique = Regex.Replace(srcFile, @"\A" + a + "|" + z + @"\Z", "");
						dstFile = Common.PathCombine(inDst, unique);
					}

					//create the final destination directory if it doesnt exist
					if (!Directory.Exists(dstFile))
						Directory.CreateDirectory(dstFile);

					//if the rename option is selected use the UniqueName which is the UniqueId (required) and UniqueTimeStamp (generated)						
					if (!string.IsNullOrEmpty(inRename))
					{
						string insert = "";
						if (srcFiles.Length > 1)
							insert = "." + Path.GetFileNameWithoutExtension(srcFile);
						dstFile = Common.PathCombine(dstFile, inRename + insert + Path.GetExtension(srcFile));
					}
					else
						dstFile = Common.PathCombine(dstFile, Path.GetFileName(srcFile));

					//change any .wtl files to .xml files
					if (Path.GetExtension(srcFile) == ".wtl")
						Path.ChangeExtension(dstFile, ".wtl.xml");

					string s = Path.GetFullPath(srcFile);
					string d = Path.GetFullPath(dstFile);
					string sd = Path.GetDirectoryName(s);
					string dd = Path.GetDirectoryName(d);

					//copy the file
					try
					{
						File.Copy(srcFile, dstFile, true);
					}
					catch (System.IO.PathTooLongException ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }

					//record the failures
					if (!File.Exists(dstFile))
					{
						//Logger.ForAll.
						//WriteLine("Failed to copy: ").
						//WriteLine("src: " + srcFile + " to").
						//WriteLine("dst: " + dstFile);
					}
					else
						files.Add(dstFile);
				}
			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }

			return files.ToArray();
		}
		#endregion copy files

		#region move files
		public static string[] MoveFiles(string inSrc, string inDst, SearchOption inSearchOption, params string[] inPatterns)
		{
			return MoveFiles(inSrc, inDst, null, inSearchOption, -1.0, null, inPatterns);
		}
		public static string[] MoveFiles(string inSrc, string inDst, string inRename, SearchOption inSearchOption, params string[] inPatterns)
		{
			return MoveFiles(inSrc, inDst, inRename, inSearchOption, -1.0, null, inPatterns);
		}
		public static string[] MoveFiles(string inSrc, string inDst, string inRename, SearchOption inSearchOption, double inMaxFileSize, params string[] inPatterns)
		{
			return MoveFiles(inSrc, inDst, inRename, inSearchOption, inMaxFileSize, null, inPatterns);
		}
		public static string[] MoveFiles(string inSrc, string inDst, SearchOption inSearchOption, string[] inExclusions, params string[] inPatterns)
		{
			return MoveFiles(inSrc, inDst, null, inSearchOption, -1.0, inExclusions, inPatterns);
		}
		public static string[] MoveFiles(string inSrc, string inDst, string inRename, SearchOption inSearchOption, double inMaxFileSize, string[] inExclusions, params string[] inPatterns)
		{
			string[] files = CopyFiles(inSrc, inDst, inRename, inSearchOption, inMaxFileSize, inExclusions, inPatterns);

			string[] deleted = DeleteFiles(inSrc, inSearchOption, inPatterns);

			//foreach (string file in files)
			//{
			//    string top = Regex.Replace(file, Common.StringToRegexPattern(inDst), "");
			//    string del = Common.PathCombine(inSrc, top);
			//    if (File.Exists(del))
			//        File.Delete(del);
			//}
			return files;
		}
		#endregion move files

		#region delete files
		public static string[] DeleteFiles(string inSrc, SearchOption inSearchOption, params string[] inPatterns)
		{
			List<string> files = new List<string>();

			foreach (string pattern in inPatterns)
			{
				string[] delFiles = Directory.GetFiles(inSrc, pattern, inSearchOption);
				foreach (string delFile in delFiles)
				{
					if (File.Exists(delFile))
						File.Delete(delFile);
				}
			}

			return files.ToArray();
		}
		#endregion delete files

		#region class property reflection
		public static bool AssertNx2(object[][] inObjectArrayNx2)
		{
			if (Common.IsNullOrEmpty(inObjectArrayNx2))
				return false;

			if (inObjectArrayNx2.GetLength(1) != 2)
				return false;

			return true;
		}
		public static bool Assert2xN(object[][] inObjectArray2xN)
		{
			if (Common.IsNullOrEmpty(inObjectArray2xN))
				return false;

			if (inObjectArray2xN.GetLength(0) != 2)
				return false;

			return true;
		}

		public static PropertyInfo[] GetProperties(object inObj, Func<PropertyInfo, bool> inPredicate)
		{
			PropertyInfo[] pis = ((IEnumerable<PropertyInfo>)inObj.GetType().GetProperties().Where(inPredicate)).ToArray();
			return pis;
		}
		public static FieldInfo[] GetFields(object inObj, Func<FieldInfo, bool> inPredicate)
		{
			FieldInfo[] fis = ((IEnumerable<FieldInfo>)inObj.GetType().GetFields().Where(inPredicate)).ToArray();
			return fis;
		}

		public static KeyValuePair<string, object>[] OutputKeyValuePairs(object inObj, Func<PropertyInfo, bool> inPredicate)
		{
			List<KeyValuePair<string, object>> kvps = new List<KeyValuePair<string, object>>();
			object[][] pairs = OutputObjectArraysNx2(inObj, inPredicate);
			foreach (object[] pair in pairs)
				kvps.Add(new KeyValuePair<string, object>(pair[0] as string, pair[1]));
			return kvps.ToArray();
		}
		public static object[][] OutputObjectArraysNx2(object inObj, Func<PropertyInfo, bool> inPredicate)
		{
			object[][] arrays = null;

			string[] names = GetPropertyNames(inObj, inPredicate);
			object[] values = GetPropertyValues(inObj, inPredicate);
			arrays = new object[names.Length][];

			for (int index = 0; index < names.Length; ++index)
				arrays[index] = new object[] { names[index], values[index] };

			return arrays;
		}
		public static object[][] OutputObjectArrays2xN(object inObj, Func<PropertyInfo, bool> inPredicate)
		{
			object[][] arrays = null;

			string[] names = GetPropertyNames(inObj, inPredicate);
			object[] values = GetPropertyValues(inObj, inPredicate);
			arrays = new object[2][] { null, null };

			arrays[0] = names;
			arrays[1] = values;

			return arrays;
		}

		public static string[] GetPropertyNames(object inObj, Func<PropertyInfo, bool> inPredicate)
		{
			PropertyInfo[] pis = GetProperties(inObj, inPredicate);
			List<string> names = new List<string>();
			foreach (PropertyInfo pi in pis) { names.Add(pi.Name); }
			return names.ToArray();
		}
		public static object[] GetPropertyValues(object inObj, Func<PropertyInfo, bool> inPredicate)
		{
			PropertyInfo[] pis = GetProperties(inObj, inPredicate);
			List<object> values = new List<object>();
			foreach (PropertyInfo pi in pis) { values.Add(pi.GetValue(inObj, new object[] { })); }
			return values.ToArray();
		}
		#endregion class property reflection

		public static double GetFileSizeInMB(string filename)
		{
			double totalBytes = 0;
			double bytesPerMegabyte = 1048576;
			FileInfo fi = new FileInfo(filename);
			totalBytes += fi.Length;
			// Calc size in megabytes
			double megaBytes = (double)(totalBytes / bytesPerMegabyte);
			// Round to three digits
			megaBytes = Math.Round(megaBytes, 3);
			return megaBytes;
		}

		#region EntryValue pairs
		public static bool ExtractEntryValue<T>(string inPair, ref T outValue)
		{
			return ExtractEntryValue<T>(inPair, ref outValue, SEPARATOR);
		}
		public static bool ExtractEntryValue<T>(string inPair, ref T outValue, string inSeparator)
		{
			bool result = false;
			try
			{

			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }
			return result;
		}


		public static bool ExtractEntryValuePair<T>(string inPair, string inEntry, ref T outValue)
		{
			return ExtractEntryValuePair<T>(inPair, inEntry, ref outValue, SEPARATOR);
		}
		public static bool ExtractEntryValuePair<T>(string inPair, string inEntry, ref T outValue, string inSeparator)
		{
			bool result = false;
			try
			{
				Match match = Regex.Match(inPair, "(" + inPair + ")(" + inSeparator + ")(.*)");
				if (match.Groups.Count == 4)
				{
					TypeConverter tc = TypeDescriptor.GetConverter(typeof(T));
					outValue = (T)tc.ConvertFromInvariantString(match.Groups[3].Value);
					result = true;
				}
			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }
			return result;
		}

		public static string CreateEntryValuePair(object inType, string inValue)
		{
			return CreateEntryValuePair(inType, inValue, SEPARATOR);
		}
		public static string CreateEntryValuePair(object inType, string inValue, string inSeparator)
		{
			return inType.ToString() + inSeparator + inValue;
		}
		public static bool TestEntryFromPair(string inTest, string inPair)
		{
			return TestEntryFromPair(inTest, inPair, SEPARATOR);
		}
		public static bool TestEntryFromPair(string inTest, string inPair, string inSeparator)
		{
			string entry = null;
			ExtractEntryFromPair(inPair, ref entry);
			return entry == inTest;
		}
		public static bool ExtractEntryFromPair(string inPair, ref string outEntry)
		{
			return ExtractEntryFromPair(inPair, ref outEntry, SEPARATOR);
		}
		public static bool ExtractEntryFromPair(string inPair, ref string outEntry, string inSeparator)
		{
			bool result = false;
			try
			{
				string[] entryAndValue = null;
				if (ExtractEntryValuePair(inPair, ref entryAndValue, inSeparator) && entryAndValue != null && entryAndValue.Length == 2)
				{
					outEntry = entryAndValue[0];
					result = true;
				}
			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }
			return result;
		}

		public static bool ExtractValueFromPair(string inPair, ref string outValue)
		{
			return ExtractValueFromPair(inPair, ref outValue, SEPARATOR);
		}
		public static bool ExtractValueFromPair(string inPair, ref string outValue, string inSeparator)
		{
			bool result = false;
			try
			{
				string[] entryAndValue = null;
				if (ExtractEntryValuePair(inPair, ref entryAndValue, inSeparator) && entryAndValue != null && entryAndValue.Length == 2)
				{
					outValue = entryAndValue[1];
					result = true;
				}
			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }
			return result;
		}
		public static bool ExtractValueFromPair(string inPair, string inEntry, ref string outValue)
		{
			return ExtractValueFromPair(inPair, inEntry, ref outValue, SEPARATOR);
		}
		public static bool ExtractValueFromPair(string inPair, string inEntry, ref string outValue, string inSeparator)
		{
			bool result = false;

			if (inEntry == null)
				return result;

			string[] entryAndValue = null;
			if (ExtractEntryValuePair(inPair, ref entryAndValue, inSeparator))
			{
				if (entryAndValue != null && entryAndValue.Length == 2 && entryAndValue[0] == inEntry)
				{
					outValue = entryAndValue[1];
					result = true;
				}
			}
			return result;
		}
		public static bool ExtractEntryValuePair(string inPair, ref string[] outEntryAndValue)
		{
			return ExtractEntryValuePair(inPair, ref outEntryAndValue, SEPARATOR);
		}
		public static bool ExtractEntryValuePair(string inPair, ref string[] outEntryAndValue, string inSeparator)
		{
			bool result = false;
			try
			{
				Match match = Regex.Match(inPair, "(.*)(" + inSeparator + ")(.*)");
				if (match.Groups.Count == 4)
				{
					outEntryAndValue = new string[] { match.Groups[1].Value, match.Groups[3].Value };
					result = true;
				}
			}
			catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }
			return result;
		}
		public static string ObjectArrayToString(object[] inItems, object inBefore, object inBetween, object inAfter)
		{
			string result = "";

			if (Common.IsNullOrEmpty(inItems))
				return result;
			//before
			result += (!IsNullOrEmpty(inBefore) ) ? inBefore.ToString() : "";
			//in between and meat
			result += (!IsNullOrEmpty(inItems[0]) ) ? inItems[0].ToString() : "";
			for (int i = 1; i < inItems.Length; ++i)
			{
				result += (!IsNullOrEmpty(inBetween)) ? inBetween : "";
				result += (!IsNullOrEmpty(inItems[i]) ) ? inItems[i].ToString() : "";
			}
			//after
			result += (!IsNullOrEmpty(inAfter) ) ? inAfter.ToString() : "";

			return result;
		}
		public static string GenericArrayToString<T>(T[] inItems, object inBefore, object inBetween, object inAfter)
		{
			List<object> objects = new List<object>();
			foreach (T item in inItems)
				objects.Add(item);
			return ObjectArrayToString(objects.ToArray(), inBefore, inBetween, inAfter);
		}
		public static string NullToEmpty(object inObject)
		{
			string result = "";
			if (inObject != null)
			{
				try
				{
					result = inObject.ToString();
				}
				catch (Exception ex) { BaseLib.OnException(new ExceptionEventArgs(ex)); }
			}
			return result;
		}

		public static bool IsNullOrEmpty(params object[] inTargets)
		{
			if (inTargets == null || inTargets.Length == 0)
				return true;
			bool result = true;
			foreach (object target in inTargets)
			{
				if (target != null)
				{
					result = false;
					break;
				}
			}
			return result;
		}
		#endregion EntryValue pairs

		//private static bool _MappedDrive = false;
		private static NetworkDrive _NetworkDrive = new NetworkDrive();
		#endregion methods

		#region fields
		public static BaseLib BaseLib = new BaseLib();
		#endregion fields

		
	}

	/// <summary>
	/// Comparer for putting files in order by CreationTime...
	/// </summary>
	public class FileCreationDateComparer : IComparer<string>
	{
		#region ctors
		public FileCreationDateComparer()
		{
		}
		#endregion ctors

		#region methods
		public int Compare(string file1, string file2)
		{
			int result = 0;
			string msg = "";
			try
			{
				FileInfo fi1 = new FileInfo(file1);
				FileInfo fi2 = new FileInfo(file2);

				DateTime dt1 = fi1.CreationTime;
				DateTime dt2 = fi2.CreationTime;


				msg = "DateTime1: " + fi1.CreationTime + " DateTime2: " + fi2.CreationTime + ">> ";
				result = DateTime.Compare(dt1, dt2);
			}
			catch (Exception ex) { /*Logger.ForVerbose.Log(ex);*/ throw ex; }
			return result;
		}
		#endregion methods
	}
}

